package com.pedro.encoder.input.gl.render.filters;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.os.Build;

import androidx.annotation.RequiresApi;

import com.pedro.encoder.R;
import com.pedro.encoder.utils.gl.GlUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public class MultiBoxBorderFilterRender extends BaseFilterRender {

  private static final int MAX_BOXES = 50;

  private final float[] squareVertexDataFilter = {
      -1f, -1f, 0f, 0f, 0f,
       1f, -1f, 0f, 1f, 0f,
      -1f,  1f, 0f, 0f, 1f,
       1f,  1f, 0f, 1f, 1f,
  };

  private int program = -1;
  private int aPositionHandle = -1;
  private int aTextureHandle = -1;
  private int uMVPMatrixHandle = -1;
  private int uSTMatrixHandle = -1;
  private int uSamplerHandle = -1;
  private int uBoxCountHandle = -1;
  private int uCentersHandle = -1;
  private int uSizesHandle = -1;
  private int uBordersHandle = -1;
  private int uColorsHandle = -1;

  private final List<float[]> centers = new ArrayList<>();
  private final List<float[]> sizes = new ArrayList<>();
  private final List<Float> borders = new ArrayList<>();
  private final List<float[]> colors = new ArrayList<>();

  public MultiBoxBorderFilterRender() {
    squareVertex = ByteBuffer.allocateDirect(squareVertexDataFilter.length * FLOAT_SIZE_BYTES)
        .order(ByteOrder.nativeOrder())
        .asFloatBuffer();
    squareVertex.put(squareVertexDataFilter).position(0);
    Matrix.setIdentityM(MVPMatrix, 0);
    Matrix.setIdentityM(STMatrix, 0);
  }

  @Override
  protected void initGlFilter(Context context) {
    String vertexShader = GlUtil.getStringFromRaw(context, R.raw.simple_vertex);
    String fragmentShader = GlUtil.getStringFromRaw(context, R.raw.multi_box_border_fragment);

    program = GlUtil.createProgram(vertexShader, fragmentShader);
    aPositionHandle = GLES20.glGetAttribLocation(program, "aPosition");
    aTextureHandle = GLES20.glGetAttribLocation(program, "aTextureCoord");
    uMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
    uSTMatrixHandle = GLES20.glGetUniformLocation(program, "uSTMatrix");
    uSamplerHandle = GLES20.glGetUniformLocation(program, "uSampler");
    uBoxCountHandle = GLES20.glGetUniformLocation(program, "uBoxCount");

    uCentersHandle = GLES20.glGetUniformLocation(program, "uCenters");
    uSizesHandle = GLES20.glGetUniformLocation(program, "uSizes");
    uBordersHandle = GLES20.glGetUniformLocation(program, "uBorders");
    uColorsHandle = GLES20.glGetUniformLocation(program, "uColors");
  }

  @Override
  protected synchronized void drawFilter() {
    GLES20.glUseProgram(program);

    squareVertex.position(SQUARE_VERTEX_DATA_POS_OFFSET);
    GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false,
        SQUARE_VERTEX_DATA_STRIDE_BYTES, squareVertex);
    GLES20.glEnableVertexAttribArray(aPositionHandle);

    squareVertex.position(SQUARE_VERTEX_DATA_UV_OFFSET);
    GLES20.glVertexAttribPointer(aTextureHandle, 2, GLES20.GL_FLOAT, false,
        SQUARE_VERTEX_DATA_STRIDE_BYTES, squareVertex);
    GLES20.glEnableVertexAttribArray(aTextureHandle);

    GLES20.glUniformMatrix4fv(uMVPMatrixHandle, 1, false, MVPMatrix, 0);
    GLES20.glUniformMatrix4fv(uSTMatrixHandle, 1, false, STMatrix, 0);

    int count = Math.min(centers.size(), MAX_BOXES);
    GLES20.glUniform1i(uBoxCountHandle, count);

    float[] centersArray = new float[count * 2];
    float[] sizesArray = new float[count * 2];
    float[] bordersArray = new float[count];
    float[] colorsArray = new float[count * 4];

    for (int i = 0; i < count; i++) {
      centersArray[i * 2] = centers.get(i)[0];
      centersArray[i * 2 + 1] = centers.get(i)[1];
      sizesArray[i * 2] = sizes.get(i)[0];
      sizesArray[i * 2 + 1] = sizes.get(i)[1];
      bordersArray[i] = borders.get(i);
      colorsArray[i * 4] = colors.get(i)[0];
      colorsArray[i * 4 + 1] = colors.get(i)[1];
      colorsArray[i * 4 + 2] = colors.get(i)[2];
      colorsArray[i * 4 + 3] = colors.get(i)[3];
    }

    GLES20.glUniform2fv(uCentersHandle, count, centersArray, 0);
    GLES20.glUniform2fv(uSizesHandle, count, sizesArray, 0);
    GLES20.glUniform1fv(uBordersHandle, count, bordersArray, 0);
    GLES20.glUniform4fv(uColorsHandle, count, colorsArray, 0);

    GLES20.glUniform1i(uSamplerHandle, 4);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, previousTexId);
  }

  @Override
  public void release() {
    GLES20.glDeleteProgram(program);
  }

  /** 添加一个检测框 */
  public synchronized void  addBox(float centerXPercent, float centerYPercent,
                     float widthPercent, float heightPercent,
                     float borderPercent,
                     float r, float g, float b, float a) {
    if (centers.size() >= MAX_BOXES) return;
    centers.add(new float[]{centerXPercent , centerYPercent });
    sizes.add(new float[]{widthPercent , heightPercent });
    borders.add(borderPercent );
    colors.add(new float[]{r, g, b, a});
  }

  /** 清空所有检测框 */
  public synchronized void clearBoxes() {
    centers.clear();
    sizes.clear();
    borders.clear();
    colors.clear();
  }
}
